(:
  A procedure to detect patterns in a display file
:)

import module namespace
    jj = "http://kumquat.emse.fr/utilitaires"
    at "jjutils.xq" ;

declare boundary-space strip;
declare variable $file := $arguments[1];
declare variable $facetnames := fn:tokenize($arguments[2],",");
declare variable $window := xs:integer($arguments[3]);
declare variable $seqlen := xs:integer($arguments[4]);

declare function local:make-token($item as item()) {
	let $elemseq := for $info in $item/info[@name = $facetnames] return xs:string($info)
	return fn:string-join($elemseq,",")
}

declare function local:calculate-sequences ($context as xs:string*, $number as xs:integer, $current as element()) as item()* 
		{
			if ($number = 0) then $current (: stop recursion :)
			else if (fn:empty($context)) then () (: not enough to grant complete sequence :)
			else
				for $val at $pos in $context 
				where not(some $value in $context[fn:position() < $pos] satisfies $value = $val)
				return
				let $newcurrent := <list>{
					($current/item,
					<item>{$val}</item>)}</list>
				return
					local:calculate-sequences($context[fn:position() > $pos], $number - 1, $newcurrent)
		};

<display>{
let $items := doc($file)/display/item
let $values := for $item in $items return local:make-token($item)
let $sequences :=
	for $val at $pos in $values
	let $init := <list><item>{$val}</item></list>
	let $window := $values[fn:position() = ($pos+1 to $pos+$window - 1)]
	return 
		local:calculate-sequences($window,$seqlen - 1,$init)

let $uniqueseqs := fn:distinct-values($sequences)

let $uniquevals := fn:distinct-values($values) 
let $countvals := for $val in $uniquevals return fn:count($values[. eq $val])	
let $itemtotal := fn:count($values)


for $seq in $uniqueseqs
let $total := fn:count($sequences[. eq $seq])
let $sample := for $v in $sequences[. eq $seq][1]/item return xs:string($v)
let $pretty := string-join($sample, ' > ')
let $probs := ($countvals[fn:index-of($uniquevals,$sample[1])],
								  for $v in $sample[position()>1]
								  return $countvals[fn:index-of($uniquevals,$v)] * ($window - $seqlen + 1) div $itemtotal)
let $expected := jj:prod($probs,1)
let $delta := 100*($total - $expected) div $expected
order by $total descending
(:order by fn:abs($delta) descending:)
return
  <item>{
    <info name="sequence">{$pretty}</info>,
    <info name="total">{$total}</info>,
    <info name="expected">{fn:round($expected)}</info>,
    <info name="difference">{fn:round($delta)}</info>
  }</item> 
}</display>
